package com.beerandjesus.sportofkings.handicapper.strategy.brisnet.singlefile;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;


import com.beerandjesus.sportofkings.handicapper.model.*;
import com.beerandjesus.sportofkings.handicapper.model.brisnet.singlefile.Horse;
import com.beerandjesus.sportofkings.handicapper.model.brisnet.singlefile.HorseRace;
import com.beerandjesus.sportofkings.handicapper.model.KeyTrainerStatistics;
import com.beerandjesus.sportofkings.handicapper.model.brisnet.singlefile.PastPerformance;
import com.beerandjesus.sportofkings.handicapper.model.brisnet.singlefile.Race;
import com.beerandjesus.sportofkings.handicapper.factory.profile.ProfileFactory;

public class MaidenRaceAnalysisStrategyImpl extends AbstractRaceAnalysisStrategy implements MaidenRaceAnalysisStrategy<HorseRace> {
	
	private static final BigDecimal FIVE = new BigDecimal(5);
	protected static final int SPEED_ADJ_1ST_OUT_64_PLUS = 15;
	protected static final int SPEED_ADJ_1ST_OUT_UNDER_64 = 30;

	private KeyTrainerStatisticsResolver trainerStatsResolver = new KeyTrainerStatisticsResolver();
	private SireFirstTimeStarterPercentageResolver sirePercentageResolver = new SireFirstTimeStarterPercentageResolver();
    private ProfileFactory profileFactory;

    private static final String[] TABLE_HEADERS = new String[] {
		STARTS, SIRE_TRAINER_WORKOUTS, SPEED, NAME, MORNING_LINE, AUCTION_PRICE_STUD_FEE
	}; 

	public RaceAnalysisResultVO analyze(HorseRace race) {
		RaceAnalysisResultVOImpl vo = new RaceAnalysisResultVOImpl();
		Race r = race.getRace();
		List<Horse> horses = race.getHorses();
		setCommonFields(vo, r, horses);
		ResultsTableImpl table = new ResultsTableImpl(TABLE_HEADERS);
		for (Horse h : horses) {
			Integer pp = new Integer(h.getPostPosition());
			// # of Starts
			int numStarts = h.getPastPerformances().size();
			ResultType resultType;
			if (numStarts == 0) {
				resultType = ResultType.FIRST_TIME_STARTER;
			} else if (numStarts == 1) {
				resultType = ResultType.SECOND_TIME_STARTER;
			} else {
				resultType = ResultType.OLDER_MAIDEN;
			}
			table.putValue(pp, resultType, STARTS, String.valueOf(numStarts));
			Integer speedPar = -1;
            try {
                speedPar = new Integer(r.getBrisSpeedPar());
            } catch (NumberFormatException e) {
                // Ignore
            }
            StringBuffer works = new StringBuffer();
			if (numStarts < 2) {
				// sire-trainer-workouts
				String sire = ".  ";
				if (sirePercentageResolver.isHighPercentageSire(h.getSireName())) {
					sire = "15%+";
				}
				String trainer = "";
				List<KeyTrainerStatistics> statList = h.getTrainerJockeyOwner().getKeyTrainerStatistics();
				KeyTrainerStatistics stats = trainerStatsResolver.getKeyTrainerStatistics(statList,
						r.getType(), numStarts);
				if (stats != null) {
					Float f = getFloatOrZero(stats.getWinPercentage());
					if (f.compareTo(ELEVEN) >= 0) {
						trainer = f.intValue() + "%";
					}
				}
				getSharpWorkouts(h, works);
				table.putValue(pp, resultType, SIRE_TRAINER_WORKOUTS, sire + " " + trainer + " " + works.toString());
				// Look for 1st timers where auction price >= 4 times stud fee
				String auctionSire = "";
				if (numStarts == 0) {
					BigDecimal auctionPrice = new BigDecimal(getInteger(h.getAuctionPrice(), 1));
					BigDecimal studFee = new BigDecimal(getInteger(h.getCurrentStudFee(), 1));
                    if (auctionPrice.compareTo(new BigDecimal(0)) != 0 &&
                            studFee.compareTo(new BigDecimal(0)) != 0) {
                        BigDecimal result = auctionPrice.divide(studFee, RoundingMode.HALF_EVEN);
                        if (result.compareTo(FIVE) >= 0) {
                            auctionSire = result.toString() + "x1";
                        }
                    }
				}
				table.putValue(pp, resultType, AUCTION_PRICE_STUD_FEE, auctionSire);
				// 2nd starters:
				// Speed figure improvement 9-15pts for 65+
				// Poss improvement up to 30 for <64
				int parCount = 0;
				String speed = "";
				if (numStarts == 1) {
					PastPerformance perf = h.getPastPerformances().get(0);
					String spd = perf.getBrisSpeedRating();
					try {
						Integer s = new Integer(spd);
						String notation;
						if (s >= 64) {
							s += SPEED_ADJ_1ST_OUT_64_PLUS;
							notation = "*";
						} else {
							s += SPEED_ADJ_1ST_OUT_UNDER_64;
							notation = "**";
						}
						if (s >= speedPar) {
							parCount = 1;
						}
						speed = parCount + "par " + notation + s;
					} catch (NumberFormatException e) {
                        // Ignore
                    }
				}
				table.putValue(pp, resultType, SPEED, speed);
			} else {
				// Workouts
				int sharpCount = getSharpWorkouts(h, works);
				if (sharpCount == 0) {
					works.append("no works");
				}
				// Speed analysis
				int speedParCount = 0;
				int maxSpeed = 0;
				int maxSpeedAge = 0;
				int count = 0;
				int lossCount = 0;
				for (PastPerformance perf : h.getPastPerformances()) {
					Integer finishPos;
					try {
						finishPos = new Integer(perf.getFinishPosition());
					} catch (NumberFormatException e) {
						finishPos = 99;
					}
					count++;
					lossCount++;
					if (finishPos == 1) {
						lossCount = 0;
					}
                    Integer speed = 0;
                    try {
                        speed = new Integer(perf.getBrisSpeedRating());
                    } catch (NumberFormatException e) {
                        // Ignore
                    }
                    if (speed >= speedPar) {
						speedParCount++;
					}
					if (speed > maxSpeed) {
						maxSpeedAge = count;
						maxSpeed = speed;
					}
				}
				// Discount horses with high speed a few back followed by more recent losses
				String notation = "";
				if (maxSpeedAge > 2 && lossCount >= 2) {
					notation = "-";
				}
				table.putValue(pp, resultType, SIRE_TRAINER_WORKOUTS, "    " + works.toString());
				table.putValue(pp, resultType, AUCTION_PRICE_STUD_FEE, "");
				table.putValue(pp, resultType, SPEED, speedParCount + "par " + notation + maxSpeed);
			}
			// Horse name
			table.putValue(pp, resultType, NAME, h.getName());
            morningLineOdds(h, table, pp, resultType);
            // Profiles
            List<AnalysisProfile> profs = getProfileFactory().getProfiles(race, h);
            table.putProfiles(pp, resultType, profs);
        }
		vo.setResultsTable(table);
		return vo;
	}

    public ProfileFactory getProfileFactory() {
        return profileFactory;
    }

    public void setProfileFactory(ProfileFactory profileFactory) {
        this.profileFactory = profileFactory;
    }
}
